package com.share.device.emqx.handler.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.share.common.core.constant.DeviceConstants;
import com.share.common.core.utils.StringUtils;
import com.share.device.domain.Cabinet;
import com.share.device.domain.CabinetSlot;
import com.share.device.domain.PowerBank;
import com.share.device.emqx.annotation.YEmqx;
import com.share.device.emqx.constants.EmqxConstants;
import com.share.device.emqx.handler.MessageHandler;
import com.share.device.service.ICabinetService;
import com.share.device.service.ICabinetSlotService;
import com.share.device.service.IPowerBankService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

//充电宝自主上传信息实现类 如电量等
@Slf4j
@Component
@YEmqx(topic = EmqxConstants.TOPIC_PROPERTY_POST)
public class PowerBankPostHandler implements MessageHandler {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ICabinetService cabinetService;
    @Autowired
    private ICabinetSlotService cabinetSlotService;
    @Autowired
    private IPowerBankService powerBankService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void handleMessage(JSONObject message) {
        log.info("充电宝自主上传信息: {}", message.toJSONString());

        //1.获取消息编号 加分布式锁
        String messageNo = message.getString("mNo");

        String key = "property:post:"+messageNo;
        boolean isExist = redisTemplate.opsForValue().setIfAbsent(key, messageNo, 1, TimeUnit.HOURS);
        if (!isExist){
            log.info("重复请求: {}", message.toJSONString());
            return;
        }

        //2.获取消息中的数据，slotNo  cabinetNo  powerBankNo
        String cabinetNo = message.getString("cNo"); //柜机编号
        String powerBankNo = message.getString("pNo");//充电宝编号
        String slotNo = message.getString("sNo");//插槽编号
        BigDecimal electricity = message.getBigDecimal("ety"); //获取当前电量

        //非空判断
        if (StringUtils.isEmpty(cabinetNo)
                || StringUtils.isEmpty(powerBankNo)
                || StringUtils.isEmpty(slotNo)
                || null == electricity) {
            log.info("消息中有参数为空: {}", message.toJSONString());
            return;
        }

        //3.获取相关实体类
        Cabinet cabinet = cabinetService.getByCabinetNo(cabinetNo); //柜机

        CabinetSlot cabinetSlot = cabinetSlotService.getBtSlotNo(cabinet.getId(), slotNo); //插槽

        PowerBank powerBank = powerBankService.getByPowerBankNo(powerBankNo); //充电宝

        //4.更新充电宝属性

        //更新充电宝电量
        powerBank.setElectricity(electricity);
        //根据电量判断充电宝状态（0:未投放 1：可用 2：已租用 3：充电中 4：故障） 电量>=80才可以使用
        if (electricity.subtract(DeviceConstants.ELECTRICITY_MIN).doubleValue() > 0){
            powerBank.setStatus("1"); //充电宝可用
        }else {
            powerBank.setStatus("3"); //充电中
        }
        powerBankService.updateById(powerBank);

        //5.更新柜机相关属性

        //获取柜机的有充电宝的插槽list
        LambdaQueryWrapper<CabinetSlot> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CabinetSlot::getStatus,"1")
                .eq(CabinetSlot::getCabinetId,cabinet.getId())
                .select(CabinetSlot::getPowerBankId); //只查询对应充电宝id字段

        List<CabinetSlot> slotList = cabinetSlotService.list(wrapper);

        //从插槽list中获取 powerbank id
        List<Long> powerBankIdList = new ArrayList<>();
        for (CabinetSlot slot : slotList) {
            powerBankIdList.add(slot.getPowerBankId());
        }

        //获取充电宝数量
        LambdaQueryWrapper<PowerBank> powerBankWrapper = new LambdaQueryWrapper<>();
        powerBankWrapper.in(PowerBank::getId,powerBankIdList)
                .eq(PowerBank::getStatus,"1"); //状态1：可用

        Long availableNum = powerBankService.count(powerBankWrapper);

        //更新柜机属性
        cabinet.setAvailableNum(availableNum.intValue()); //可用充电宝数量
        cabinet.setUpdateTime(new Date());

        cabinetService.updateById(cabinet);
    }
}
